﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Net.Sockets;
using System.Net;
using System.Windows.Input;
using System.Windows;
using System.Threading;
using System.IO;

namespace serial_socket_wpf.ViewModule
{
    class TcpServer_view_module : INotifyPropertyChanged
    {


        #region bondings
        private string _local_ip = null;
        private string _port = null;
        private bool _ctrl_enabled = true;
        private string _btn_string = null;
        private string _label = null;

        public string local_ip
        {
            get { return _local_ip; }
            set
            {
                if (value != _local_ip)
                {
                    _local_ip = value;
                    NotifyPropertyChanged("local_ip");
                }
            }
        }
        public string port
        {
            get { return _port; }
            set
            {
                if (value != _port)
                {
                    _port = value;
                    NotifyPropertyChanged("port");
                }
            }
        }

        public bool ctrl_enabled
        {
            get { return _ctrl_enabled; }
            set
            {
                if (value != _ctrl_enabled)
                {
                    _ctrl_enabled = value;
                    NotifyPropertyChanged("ctrl_enabled");
                }
            }
        }

        public string btn_string
        {
            get { return _btn_string; }
            set
            {
                if (value != _btn_string)
                {
                    _btn_string = value;
                    NotifyPropertyChanged("btn_string");
                }
            }
        }

        public string label
        {
            get { return _label; }
            set
            {
                if (value != _label)
                {
                    _label = value;
                    NotifyPropertyChanged("label");

                }
            }
        }
        #endregion

        private Thread thread_listener = null;
        private enum state_tcp_serve
        {
            not_started,
            waiting_client,
            connected,
        }

        private state_tcp_serve _state = state_tcp_serve.not_started;

        private TcpListener tcp_listener = null;

        public delegate void delegate_socket_recieve(byte[] src, int len);
        public event delegate_socket_recieve DataReceived;
        public Stream socket_writer = null;

        private void thread_process_tcp_listener()
        {
            try
            {
                while (true)
                {
                    state = state_tcp_serve.waiting_client;
                    tcp_listener.Start(1);
                    Socket tcp_socket = tcp_listener.AcceptSocket();
                    tcp_listener.Stop();
                    state = state_tcp_serve.connected;

                    socket_writer = new NetworkStream(tcp_socket);

                    if (tcp_socket != null)
                    {
                        while (true)
                        {
                            byte[] buffer = new byte[2048];
                            int len = tcp_socket.Receive(buffer);
                            if (len == 0)
                            {   //socket disconnect
                                tcp_socket.Dispose();
                                socket_writer = null;
                                break;
                            }
                            else
                            {
                                DataReceived(buffer, len);
                            }
                        }
                    }
                }
            }
            catch(System.Threading.ThreadAbortException abort_e)
            {
                MessageBox.Show(abort_e.Message);
                //MessageBox.Show("abort_e\r\n"
                //    + "type:\t" + abort_e.GetType()
                //    + "\r\nMessgage:\r\n" + abort_e.Message);
            }
            catch(System.Net.Sockets.SocketException socket_e)
            {
                MessageBox.Show("socket_e\r\n"
                    + "type:\t" + socket_e.GetType()
                    + "\r\nMessgage:\r\n" + socket_e.Message);
            }
            catch (System.ObjectDisposedException dispose_e)
            {
                MessageBox.Show("dispose_e\r\n"
                    + "type:\t" + dispose_e.GetType()
                    + "\r\nMessgage:\r\n" + dispose_e.Message);
            }
            catch (SystemException se)
            {
                MessageBox.Show("thread_process_tcp_listener\r\n" 
                    + "type:\t" + se.GetType()
                    +"\r\nMessgage:\r\n" + se.Message);
                state = state_tcp_serve.not_started;
            }
        }

        private state_tcp_serve state
        {
            get { return _state; }
            set
            {
                if (value != _state)
                {
                    _state = value;
                    switch (_state)
                    {
                        case state_tcp_serve.not_started:
                            ctrl_enabled = true;
                            btn_string = "start";
                            label = "click_to_start_tcp_listen";
                            break;
                        case state_tcp_serve.waiting_client:
                            ctrl_enabled = false;
                            btn_string = "abort";
                            label = "click_to_abort_tcp_listen";
                            break;
                        case state_tcp_serve.connected:
                            ctrl_enabled = false;
                            btn_string = "disconnect";
                            label = "click_to_disconnect";
                            break;
                    }
                }
            }
        }

        private void on_click()
        {
            try
            {
                switch (state)
                {
                    case state_tcp_serve.not_started:

                        IPAddress address = IPAddress.Parse(_local_ip);
                        int local_port = int.Parse(_port);
                        tcp_listener = new TcpListener(address, local_port);
                        thread_listener = new Thread(new ThreadStart(thread_process_tcp_listener));
                        thread_listener.IsBackground = true;
                        thread_listener.Start();
                        break;

                    case state_tcp_serve.waiting_client:
                        tcp_listener.Stop();
                        if (thread_listener != null)
                        {
                            thread_listener.Abort();
                        }
                        state = state_tcp_serve.not_started;
                        break;

                    case state_tcp_serve.connected:
                        state = state_tcp_serve.not_started;
                        //if (thread_listener.IsAlive)
                        //{
                            thread_listener.Abort();
                        //}
                        socket_writer = null;
                        break;
                }
            }
            catch (SystemException se)
            {
                MessageBox.Show(se.Message);
            }
        }

        #region ICommand
        private class TcpServer_view_module_command : ICommand
        {
            Action _act;

            public TcpServer_view_module_command(Action exec_process)
            {
                _act = exec_process;
            }


            public event EventHandler CanExecuteChanged;
            public bool CanExecute(object parameter)
            {
                return true;
            }
            public void Execute(object parameter)
            {
                _act();
            }

        }
        private ICommand _Command_on_click = null;
        public ICommand OnClickCommand
        {
            get
            {
                if (_Command_on_click == null)
                {
                    _Command_on_click = new TcpServer_view_module_command(on_click);
                }
                return _Command_on_click;
            }
        }
        #endregion
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion

    }
}
